package com.financing.service.invest;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.financing.common.CONST;
import com.financing.components.payment.Gateway;
import com.financing.components.sms.Sms;
import com.financing.controller.invest.TradeController;
import com.financing.enums.finance.FinanceLogType;
import com.financing.enums.invest.InvestLogType;
import com.financing.enums.notify.AgentNotify;
import com.financing.enums.notify.AssetsNotify;
import com.financing.enums.notify.SmsNotify;
import com.financing.model.Data;
import com.financing.model.invest.Bid;
import com.financing.model.invest.BidCheck;
import com.financing.model.invest.CouponLog;
import com.financing.model.invest.InvestLog;
import com.financing.model.invest.Payment;
import com.financing.model.invest.Repay;
import com.financing.model.invest.Trade;
import com.financing.model.user.User;
import com.financing.service.BaseService;
import com.financing.service.finance.FinanceLogService;
import com.financing.service.system.AssetsLogService;
import com.financing.service.system.LoggerService;
import com.financing.service.user.UserService;
import com.financing.util.DateUtil;
import com.financing.util.Money;
import com.financing.util.Str;
import com.financing.util.XmlHelper;
import com.jfinal.plugin.activerecord.Page;

public class RepayService extends BaseService<InvestLog>{
	private static BidService bid = new BidService();	
	private static UserService user = new UserService();	
	private static LoggerService log = new LoggerService();
	private static RepayService repay = new RepayService();
	private static BidCheckService bidCheck = new BidCheckService();	
	private static AssetsLogService assetsLog = new AssetsLogService();	
    private static final Logger logger = Logger.getLogger(TradeController.class);

    public synchronized static void run(int bidId) {	
 		logger.warn("还款任务开始！");
 		Set<Integer> bids = new HashSet<Integer>();
 		List<Repay> repays = bidId>0 ?  repay.findByBid(bidId) : repay.groupByBid(1, 999, Data.putStr("status","process","repayTimeEnd",DateUtil.getNowDate()+" 24:00:00")).getList();
 		for(Repay r : repays) { 
 			// 对应标的
 			logger.warn("还款的标的ID:"+r.getBidId());
 			// 获取标的
 			Bid b = Bid.me.findById(r.getBidId());
 			// 查找最新需要还的期数
 			int period = b.getApplyPerid();
 			try {
				if(b.getIsTrading()==0) {
					// 还款锁住标的
					b.setIsTrading(1).update();
					// 平台机构
					double platAvailableAmount = user.findByCode(CONST.PLAT_CODE).getAvailableAmount();
					// 融资机构
					User fund = User.me.findById(b.getFund());
					double fundAvailableAmount = fund.getAvailableAmount();
					// 获取标的所需还款金额
					Double[] repayAmount = repay.getRepayAmount(b,period);
					BidCheck bc = bidCheck.findByBid(b.getId());
					logger.error("平台需要还款==="+repayAmount[0]+"===平台余额==="+platAvailableAmount);
					logger.error("机构需要还款==="+repayAmount[1]+"===机构余额==="+fundAvailableAmount);
					
					if(platAvailableAmount>=repayAmount[0]
						&& fundAvailableAmount>=repayAmount[1]) {

						// 还款前预先划拨到中间户
						if(repayAmount[0]>0 && period>bc.getPlatRepayPeriod()) {
							XmlHelper res = Gateway.pay(CONST.PLAT_CODE, CONST.MIDDLE_ACCOUNT, repayAmount[0], "项目"+b.getName()+"平台还款", true, false);
							if(res.isSuccess()) {
								bc.setPlatRepayPeriod(period).update();
							}
						}else {
							bc.setPlatRepayPeriod(period).update();
						}
						if(repayAmount[1]>0 && period>bc.getFundRepayPeriod()) {
							XmlHelper res = Gateway.pay(fund.getCode(), CONST.MIDDLE_ACCOUNT, repayAmount[1], "项目"+b.getName()+"融资机构还款");
							if(res.isSuccess()) {
								bc.setFundRepayPeriod(period).update();
							}
						}else {
							bc.setFundRepayPeriod(period).update();
						}
						
						// 判断是否还款至中间户
						if(bc.getFundRepayPeriod()==period && bc.getPlatRepayPeriod()==period) {
							List<Repay> list = repay.findRepayByBid(b.getId(),period);
							for(Repay rp : list){
								
								// 对应交易
								Trade t = Trade.me.findById(rp.getTradeId());
								bids.add(b.getId()); 
								// 收款人
								User lender = user.getInfo(rp.getUserId());
								// 计算单笔还款金额
								double amount =  rp.getPeriodTotal();
								// 获取日期
								String date = DateUtil.format(t.getCreateTime(), DateUtil.DATE_LOCAL_FORMAT);
								
								logger.warn("还款记录ID==="+rp.getId()+" 交易记录ID==="+t.getId()+"  还款金额==="+amount+" 融资机构==="+fund.getRealName());
								
								// 插入还款记录
								Payment p = new Payment();
								p.setLender(lender.getId());
								p.setFund(fund.getId());
								p.setAmount(rp.getPeriodTotal());
								p.setTradeId(t.getId());
								p.setBidId(b.getId());
								p.setCreateTime(new Date());
								p.save();
								
								// 中间户付款到投资者：Gateway.创建托管代付交易
								logger.warn("本期还款金额==="+rp.getPeriodTotal());
								XmlHelper res = Gateway.pay(CONST.MIDDLE_ACCOUNT, lender.getCode(), rp.getPeriodTotal(), "项目"+b.getName()+"（"+rp.getApplyPeriod()+"/"+rp.getPeriod()+"）中间户还款");
								if(res.isSuccess()) {
									
									InvestLogService.build("还款", InvestLogType.REPAY, rp.getId(), amount, t.getUserId(), "success", b.getName()+(rp.getPeriod()==1?"":"("+rp.getApplyPeriod()+"/"+rp.getPeriod()+")"), res.getCode());
									
									// 更新实际还款人 & 状态
									rp.setActualRepayUserId(rp.getRepayUserId()).setActualRepayRealName(rp.getActualRepayRealName()).setStatus("success").setActualRepayTime(new Date()).update();
									
									// 插入资产记录-还款成功 
									AssetsNotify notify = AssetsNotify.REPAY_SUCCESS;
									AgentNotify agentNotify = AgentNotify.REPAY_SUCCESS;
									assetsLog.bulid(lender, notify.getName(), Str.format(notify.getContents(), date, b.getName()+"("+rp.getApplyPeriod()+"/"+rp.getPeriod()+")", rp.getPeriodTotal()), Str.format(agentNotify.getContents(), lender.getMobile()+"（"+lender.getRealName()+"）", b.getName(), rp.getPeriod(), rp.getApplyPeriod(), lender.getAvailableAmount()));
									
									// 发送体验金资产信息提醒
									if(t.getJxq()>0){
										notify = AssetsNotify.COUPON_REPAY;
										agentNotify = AgentNotify.COUPON_REPAY;
										CouponLog cl = CouponLog.me.findById(t.getJxq());
										assetsLog.bulid(lender, Str.format(notify.getName(), cl.getName()), Str.format(notify.getContents(), cl.getName(), rp.getInterest()), Str.format(agentNotify.getContents(), lender.getMobile()+"（"+lender.getRealName()+"）", cl.getName(), rp.getJxq()));
									}
									
									// 插入财务记录
									User plat = user.findByCode(CONST.PLAT_CODE);
									if(rp.getAmount()>0) {
										FinanceLogService.build(fund, lender, rp.getAmount(), res.getCode(), FinanceLogType.AMOUNT, "融资机构支付"+b.getName()+"本金还款");
									}
									if(rp.getInterest()>0) {
										FinanceLogService.build(fund, lender, rp.getInterest(), res.getCode(), FinanceLogType.INTEREST, "融资机构支付"+b.getName()+"利息还款");
									}
									if(rp.getPlus()>0) {
										FinanceLogService.build(rp.getIsPlatPlus()==1?plat:fund, lender, rp.getPlus(), res.getCode(), FinanceLogType.PLUS, (rp.getIsPlatPlus()==1?"平台":"融资机构")+"支付"+b.getName()+"加息还款");
				    				}
									if(rp.getJxq()>0) {
										FinanceLogService.build(plat, lender, rp.getJxq(), res.getCode(), FinanceLogType.JXQ, "平台支付"+b.getName()+"加息券还款");
				    				}

									// 还款成功短信
									String bidName = rp.getBidName().replace("【", "（").replace("】", "）");
									Sms.send(lender.getMobile(), Str.format(SmsNotify.REPAY_SUCCESS, bidName, rp.getPeriodTotal(), rp.getApplyPeriod(), rp.getPeriod(), CONST.find("PLAT_PHONE")));
								}
							}
							bid.setFinish(b.getId());
						}else{
							logger.error("还款金额划拨到中间户失败！");
						}
					} else {
						log.build("标的还款失败！", "余额不足，标的"+b.getId()+b.getName()+"还款失败！", fund.getId(), "backend");
						logger.error("余额不足，标的"+b.getId()+b.getName()+"还款失败！");
					}
				}
 			}catch(Exception e) {
 				logger.error(e.toString());
 				e.printStackTrace();
 			}finally {
 				b.setIsTrading(0).update();
 			}
 		}
     }
    
	/**
	 * 获取等待还款的记录
	 */
	public List<Repay> findRepayByBid(int bidId, int period) {
		return Repay.me.find("select * from repay where status='process' and bid_id=? and apply_period=?", bidId, period);
	}

	/**
	 * 计算交易收益总额
	 */
	public double sumByTrade(int id) {
		Repay rp = Repay.me.findFirst("select sum(amount) as total from repay where status='process' and trade_id=?",id);		
		return Money.get(rp.getDouble("total"));
	}

	/**
	 * 分页信息
	 * @param map 
	 * @return Page<Repay>
	 */
	public Page<Repay> list(int page, int size, Map<String, String> map) {
		String orderBy = " order by status asc, repay_time asc";
		if(Str.eq("repaying", map.get("status"))) {
			orderBy = " order by repay_time asc";
		}else if(Str.eq("finish", map.get("status"))) {
			orderBy = " order by repay_time desc";
		}
		return Repay.me.paginate(page, size, buildSql("repay",Arrays.asList("status", "actual_repay_time", "repay_time", "create_time", "real_name", "mobile", "bid_name"),map,orderBy));
	}

	/**
	 * 根据标的分组
	 * @param page
	 * @param size
	 * @param map
	 * @return Page<Repay>
	 */
	public Page<Repay> groupByBid(int page, int size, Map<String, String> map) {
		return Repay.me.paginate(page, size, buildSql("select bid_id, sum(period_total) total, sum(amount) amount, sum(interest) interest,sum(plus) plus,sum(jxq) jxq, repay_time, create_time, repay_user_id ", "repay",Arrays.asList("actual_repay_time", "repay_time", "create_time", "real_name", "status", "mobile", "bid_name"),map," AND status='process' group by bid_id order by repay_time asc "));
	}

	/**
	 * 根据客服查找信息
	 * @param page
	 * @param size
	 * @param map
	 * @return Page<Repay>
	 */
	public Page<Repay> findByAgent(int page, int size, String agents, String start, String end, String mobile, String status, String name) {
		String where = " 1=1 ";
		if(Str.nb(mobile)) {
			where += " and mobile='"+mobile+"'";
		}
		if(Str.nb(status)) { 
			where += " and status='"+status+"'";
		}
		if(Str.nb(name)) {
			where += " and name like '%"+name+"%'";
		}
		return Repay.me.paginate(page, size, "select *", "from repay where "+where+" and user_id in (select id from (select distinct id from user where agent_id in ("+agents+")) as tmp) and repay_time>=? and repay_time<=? order by create_time desc ", start, end);
	}

	/**
	 * 统计所有投资金额
	 */
	public double total() {
		Repay r = Repay.me.findFirst("select sum(interest+plus+jxq) as total from repay where status='success'");
		InvestLog log = InvestLog.me.findFirst("select sum(amount) as total from invest_log where type='xjhb' or type='tzhb'");
		return Money.format(Money.get(r.get("total"))+Money.get(log.get("total")));
	}
	
	/**
	 * 获取等待还款的记录
	 */
	public List<Repay> findByBid(int bidId) {
		return Repay.me.find("select * from repay where bid_id=? and status='process' order by create_time DESC limit 0,1", bidId);
	}

	/**
	 * 获取等待还款的记录
	 */
	public List<Repay> findTargetByBid(int bidId, int period) {
		return Repay.me.find("select * from repay where status='process' and bid_id=? and apply_period=?",bidId,period);
	}
	
	/**
	 * 获取等待还款的记录的总金额
	 */
	public double sumTargetByBid(int bidId) {
		Repay rp = Repay.me.findFirst("select sum(amount+interest+plus) as total from repay where status='process' AND bid_id=?",bidId);		
		return Money.get(rp.getDouble("total"));
	}

	public Repay count(Map<String, String> map) {
		return Repay.me.findFirst(buildSql("SELECT sum(total) as total, sum(amount) as amount, sum(interest) as interest, sum(plus) as plus, sum(jxq) as jxq ", "repay",Arrays.asList("actual_repay_time", "repay_time", "create_time", "real_name", "mobile", "bid_name"),map));
	}
	
	/**
	 * 计算总金额 & 检查借款机构钱够不够
	 * @param b
	 * @return
	 * @throws Exception
	 */
    public Double[] getRepayAmount(Bid b,int period) throws Exception{
		List<Repay> list = this.findTargetByBid(b.getId(),period);
		double total1 = 0.0;
		double total2 = 0.0;
		
		for(Repay rp : list) {
			// 统计融资机构总计要付的金额
			Map<String, Double> repayMap = new HashMap<String, Double>();
			repayMap.put("amount", rp.getAmount());
			repayMap.put("interest", rp.getInterest());
			repayMap.put("plus", rp.getPlus());
			repayMap.put("jxq", rp.getJxq());

			for(String k : repayMap.keySet()){;
				double dm = repayMap.get(k);
				if(b.isExperi() || Str.eq("jxq", k) || (Str.eq("plus", k) && rp.getIsPlatPlus()==1)) {
					total1 = Money.add(total1, dm);
				} else{
					total2 = Money.add(total2, dm);
				}
			}
		}
		return new Double[] {Money.format(total1),Money.format(total2)};
    }
    
	/**
	 * 计算用户代还款金额
	 */
	public List<Repay> findByUser(int userId,String month) {
		String where = "status='process'";
		if(Str.nb(month)) {
			where += " and repay_time>='"+month+"-01 00:00:00' and repay_time<='"+month+"-31 23:59:59'";
		}
		return Repay.me.find("select * from repay where "+where+" and user_id=? order by repay_time asc",userId);
	}

	/**
	 * 根据条件获取总金额
	 */
	public List<Repay> findByParams(Map<String, String> map) {
		
		return Repay.me.find(buildSql("repay",Arrays.asList("status", "actual_repay_time", "repay_time", "create_time", "real_name", "mobile", "bid_name"),map));
	}
}
